{{!

  Copyright (c) Meta Platforms, Inc. and affiliates.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

}}{{!
}}{{#let function_comma = (if function:params.fields? ", " null)}}
template <typename CallbackType>
folly::SemiFuture<{{> types/return_type_client_lift_unit}}> {{> service_common/client_class_name}}::fbthrift_semifuture_{{function:cpp_name}}(apache::thrift::RpcOptions& rpcOptions{{function_comma}}{{> service_common/function_param_list_client}}) {
  using CallbackHelper = apache::thrift::detail::FutureCallbackHelper<{{> types/return_type_client_no_handle_lift_unit}}>;
  folly::Promise<CallbackHelper::PromiseResult> promise;
  auto semifuture = promise.getSemiFuture();
  auto ctxAndHeader = {{function:cpp_name}}Ctx(&rpcOptions);
{{#function:oneway?}}
  auto wrappedCallbackAndContextStack = apache::thrift::GeneratedAsyncClient::template prepareRequestClientCallback<true /* kIsOneWay */>(
    std::make_unique<CallbackType>(std::move(promise), channel_),
    std::move(ctxAndHeader.first));
{{/function:oneway?}}
{{^function:oneway?}}
  auto wrappedCallbackAndContextStack = apache::thrift::GeneratedAsyncClient::template prepareRequestClientCallback<false /* kIsOneWay */>(
    std::make_unique<CallbackType>(std::move(promise), recv_wrapped_{{function:cpp_name}}, channel_),
    std::move(ctxAndHeader.first));
{{/function:oneway?}}
  auto header = std::move(ctxAndHeader.second);
  auto* contextStack = wrappedCallbackAndContextStack.second;
{{#function:stream?}}
  auto wrappedCallback = apache::thrift::createStreamClientCallback(std::move(wrappedCallbackAndContextStack.first), rpcOptions.getBufferOptions());
{{/function:stream?}}{{^function:stream?}}
  auto wrappedCallback = std::move(wrappedCallbackAndContextStack.first);
{{/function:stream?}}
{{#function:creates_interaction?}}
  {{function:created_interaction}} interactionHandle(channel_, "{{function:created_interaction}}", interceptors_);
{{/function:creates_interaction?}}
  std::unique_ptr<folly::IOBuf> interceptorFrameworkMetadata = nullptr;
  if (contextStack != nullptr) {
    auto argsAsRefs = std::tie({{> service_common/param_list}});
    if (auto exTry = contextStack->processClientInterceptorsOnRequest(apache::thrift::ClientInterceptorOnRequestArguments(argsAsRefs), header.get(), rpcOptions);
        exTry.hasException()) {
      return folly::makeSemiFuture<{{> types/return_type_client_lift_unit}}>(std::move(exTry).exception());
    }
    interceptorFrameworkMetadata = detail::ContextStackUnsafeAPI(*contextStack).getInterceptorFrameworkMetadata(rpcOptions);
  }
  apache::thrift::SerializedRequest request = fbthrift_serialize_{{function:cpp_name}}(rpcOptions, *header, contextStack{{function_comma}}{{> service_common/param_list}});
  fbthrift_send_{{function:cpp_name}}(std::move(request), rpcOptions, std::move(header), std::move(wrappedCallback), std::move(interceptorFrameworkMetadata){{#function:creates_interaction?}}, interactionHandle{{/function:creates_interaction?}});
{{#if (not function:creates_interaction?)}}
  return std::move(semifuture).deferValue(CallbackHelper::processClientInterceptorsAndExtractResult);
{{#else}}
  return std::move(semifuture)
      .deferValue(
          [interactionHandle = std::move(interactionHandle)](CallbackHelper::PromiseResult&& result) mutable {
          auto returnValue = CallbackHelper::processClientInterceptorsAndExtractResult(std::move(result));
          returnValue.throwUnlessValue();
          {{#if type:void?}}
            {{#if function:stream?}}
            return std::pair{std::move(interactionHandle), std::move(*returnValue)};
            {{#else}}
            return std::move(interactionHandle);
            {{/if function:stream?}}
          {{#else}}
            return std::pair{std::move(interactionHandle), std::move(*returnValue)};
          {{/if type:void?}}
          });
{{/if (not function:creates_interaction?)}}
}

{{^service:reduced_client?}}{{^function:creates_interaction?}}
{{^function:stream?}}
folly::Future<{{> types/return_type_client_lift_unit}}> {{> service_common/client_class_name}}::future_{{function:cpp_name}}({{> service_common/function_param_list_client}}) {
  ::apache::thrift::RpcOptions rpcOptions;
  return future_{{function:cpp_name}}(rpcOptions{{function_comma}}{{> service_common/param_list}});
}
{{/function:stream?}}

{{/function:creates_interaction?}}{{/service:reduced_client?}}
folly::SemiFuture<{{> types/return_type_client_lift_unit}}> {{> service_common/client_class_name}}::semifuture_{{function:cpp_name}}({{> service_common/function_param_list_client}}) {
  ::apache::thrift::RpcOptions rpcOptions;
  return semifuture_{{function:cpp_name}}(rpcOptions{{function_comma}}{{> service_common/param_list}});
}
{{^service:reduced_client?}}{{^function:creates_interaction?}}

{{^function:stream?}}
folly::Future<{{> types/return_type_client_lift_unit}}> {{> service_common/client_class_name}}::future_{{function:cpp_name}}(apache::thrift::RpcOptions& rpcOptions{{function_comma}}{{> service_common/function_param_list_client}}) {
{{#function:oneway?}}
  using CallbackType = apache::thrift::OneWayFutureCallback;
{{/function:oneway?}}
{{^function:oneway?}}
  using CallbackType = apache::thrift::FutureCallback<{{> types/return_type_client_lift_unit}}>;
{{/function:oneway?}}
  return fbthrift_semifuture_{{function:cpp_name}}<CallbackType>(rpcOptions{{function_comma}}{{> service_common/param_list}}).toUnsafeFuture();
}
{{/function:stream?}}
{{/function:creates_interaction?}}{{/service:reduced_client?}}

folly::SemiFuture<{{> types/return_type_client_lift_unit}}> {{> service_common/client_class_name}}::semifuture_{{function:cpp_name}}(apache::thrift::RpcOptions& rpcOptions{{function_comma}}{{> service_common/function_param_list_client}}) {
{{#function:oneway?}}
  using CallbackType = apache::thrift::OneWaySemiFutureCallback;
{{/function:oneway?}}
{{^function:oneway?}}
  using CallbackType = apache::thrift::SemiFutureCallback<{{> types/return_type_client_no_handle_lift_unit}}>;
{{/function:oneway?}}
  return fbthrift_semifuture_{{function:cpp_name}}<CallbackType>(rpcOptions{{function_comma}}{{> service_common/param_list}});
}

{{#function:creates_interaction?}}
std::pair<
  apache::thrift::Client<{{service:parent_service_qualified_name}}>::{{function:created_interaction}},
  folly::SemiFuture<{{> types/return_type_client_no_handle_lift_unit}}>
> {{> service_common/client_class_name}}::eager_semifuture_{{function:cpp_name}}(apache::thrift::RpcOptions& rpcOptions{{function_comma}}{{> service_common/function_param_list_client}}) {
  auto callbackAndFuture = makeSemiFutureCallback(recv_wrapped_{{function:cpp_name}}, channel_);
  {{function:created_interaction}} interactionHandle(channel_, "{{function:created_interaction}}", interceptors_);
  auto callback = std::move(callbackAndFuture.first);
  {{function:cpp_name}}(rpcOptions, std::move(callback){{#function:creates_interaction?}}, interactionHandle{{/function:creates_interaction?}}{{function_comma}}{{> service_common/param_list}});
  return std::make_pair(std::move(interactionHandle), std::move(callbackAndFuture.second));
}

{{/function:creates_interaction?}}
{{#function:has_deprecated_header_client_methods}}{{^function:oneway?}}{{#function:legacy_client_methods?}}
{{^function:stream?}}
folly::Future<std::pair<{{> types/return_type_client_lift_unit}}, std::unique_ptr<apache::thrift::transport::THeader>>> {{> service_common/client_class_name}}::header_future_{{function:cpp_name}}(apache::thrift::RpcOptions& rpcOptions{{function_comma}}{{> service_common/function_param_list_client}}) {
  using CallbackHelper = apache::thrift::detail::FutureCallbackHelper<std::pair<{{> types/return_type_client_lift_unit}}, std::unique_ptr<apache::thrift::transport::THeader>>>;
  folly::Promise<CallbackHelper::PromiseResult> promise;
  auto future = promise.getFuture();
  auto callback = std::make_unique<apache::thrift::HeaderFutureCallback<{{> types/return_type_client_lift_unit}}>>(std::move(promise), recv_wrapped_{{function:cpp_name}}, channel_);
  {{function:cpp_name}}(rpcOptions, std::move(callback){{function_comma}}{{> service_common/param_list}});
  return std::move(future).thenValue(CallbackHelper::processClientInterceptorsAndExtractResult);
}
{{/function:stream?}}

folly::SemiFuture<std::pair<{{> types/return_type_client_lift_unit}}, std::unique_ptr<apache::thrift::transport::THeader>>> {{> service_common/client_class_name}}::header_semifuture_{{function:cpp_name}}(apache::thrift::RpcOptions& rpcOptions{{function_comma}}{{> service_common/function_param_list_client}}) {
  auto callbackAndFuture = makeHeaderSemiFutureCallback(recv_wrapped_{{function:cpp_name}}, channel_);
  auto callback = std::move(callbackAndFuture.first);
  {{function:cpp_name}}(rpcOptions, std::move(callback){{function_comma}}{{> service_common/param_list}});
  return std::move(callbackAndFuture.second);
}
{{/function:legacy_client_methods?}}{{/function:oneway?}}{{/function:has_deprecated_header_client_methods}}
